package server

//
import (
	"database/sql"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/jmoiron/sqlx"
	"io"
	"os"
	"path/filepath"
	"time"
)

const enableHttps = false //是否开启https

func RunServer(db *sqlx.DB) {
	//此服务器一次异常不会整个崩溃
	gin.DisableConsoleColor()

	// Logging to a file.
	f, _ := os.Create("gin.log")
	gin.DefaultWriter = io.MultiWriter(f, os.Stdout)

	r := gin.Default()
	r.POST("/form", func(c *gin.Context) {
		//json格式数据
		var outData OutData
		if err := c.ShouldBindJSON(&outData); err != nil {
			c.JSON(200, FailRet(CodeParamError, "out parse failed: "+err.Error()))
			return
		}

		if outData.Method == "" {
			c.JSON(200, FailRet(CodeParamError, "method is empty"))
			return
		}

		tx, err := db.Begin() //每个请求都是一个事务
		if err != nil {
			c.JSON(200, FailRet(CodeDatabaseError, "start transaction error!"))
			return
		}
		//捕获整个程序的异常，异常发生时回滚事务，并返回http。
		defer func() {
			if p := recover(); p != nil {
				tx.Rollback()
				c.JSON(200, FailRet(CodeCollapse, p))
				return
			}
		}()

		var ret *ReturnStruct
		switch outData.Method {
		case "code_login":
			//不带session的方法放在外面
			ret = code_login(tx, outData.JsonData)
		case "test222":
			ret = test222(tx, outData.JsonData)
		default:
			//带session的方法放在里面
			ret = RequestWithSession(tx, outData.Method, outData.Session, outData.JsonData)
		}

		if ret != nil && ret.is_success() {
			err = tx.Commit()
			if err != nil {
				c.JSON(200, FailRet(CodeDatabaseError, "commit transaction error!"))
				return
			}
		} else {
			err = tx.Rollback()
			fmt.Println("===", err)
		}

		c.JSON(200, ret)
	})

	if enableHttps {
		work_dir, err := os.Getwd()
		if err != nil {
			fmt.Println("work_dir err: ", err)
		}
		fmt.Println(work_dir)

		//用的阿里云的证书
		crtPath, err1 := filepath.Abs(work_dir + "/4944259_giveworld.cn.pem") //.crt文件路径
		if err1 != nil {
			fmt.Println("server.crt未找到：", err)
			return
		}

		keyPath, err2 := filepath.Abs(work_dir + "/4944259_giveworld.cn.key") //.key文件路径
		if err2 != nil {
			fmt.Println("server.key未找到：", err)
			return
		}

		r.RunTLS(":8000", crtPath, keyPath)
	} else {
		r.Run(":8000")
	}
}

func test222(tx *sql.Tx, jsonData string) *ReturnStruct {
	tx.Exec("update tb_session set session_id = 'abc-----' where person_id = 10001")
	panic(111)
	return FailRet(CodeSvrERROR, "")
}

// 定义接收数据的结构体
type OutData struct {
	// binding:"required"修饰的字段，若接收为空值，则报错，是必须字段
	Method   string `json:"method" binding:"required"`
	Session  string `json:"session"`
	JsonData string `json:"json" binding:"required"`
}

func RequestWithSession(tx *sql.Tx, method string, session string, jsonData string) *ReturnStruct {

	if len(session) == 0 {
		return FailRet(CodeSessionError, errors.New("session is empty."))
	}

	var UserId int64
	var CreateDate []uint8
	err := tx.QueryRow("select person_id, create_date from tb_session where session_id=?", session).Scan(&UserId, &CreateDate)
	if err != nil {
		if err.Error() == sql.ErrNoRows.Error() {
			return FailRet(CodeSessionError, "本地session错误")
		} else {
			return FailRet(CodeDatabaseError, err)
		}
	}

	var create_date time.Time
	create_date, err = ParseDBDate(CreateDate)
	if err != nil {
		return FailRet(CodeSvrERROR, err)
	}

	if IsSessionExpired(create_date) {
		return FailRet(CodeSessionExpired, nil)
	}

	person_id := UserId
	var ret *ReturnStruct
	switch method {
	case "session_login":
		ret = session_login(tx, person_id, jsonData)
	case "select_family":
		ret = select_family(tx, person_id, jsonData)
	case "get_family_list":
		ret = get_family_list(tx, person_id, jsonData)
	case "get_person_attrs":
		ret = get_person_attrs(tx, person_id, jsonData)
	case "set_person_attrs":
		ret = set_person_attrs(tx, person_id, jsonData)
	case "get_person_vals":
		ret = get_person_vals(tx, person_id, jsonData)
	case "set_person_vals":
		ret = set_person_vals(tx, person_id, jsonData)
	case "add_person_pic":
		ret = add_person_pic(tx, person_id, jsonData)
	case "del_person_pic":
		ret = del_person_pic(tx, person_id, jsonData)
	case "get_person_pic":
		ret = get_person_pic(tx, person_id, jsonData)
	case "get_article_info":
		ret = get_article_info(tx, person_id, jsonData)
	case "edit_article_info":
		ret = edit_article_info(tx, person_id, jsonData)
	case "edit_article_title":
		ret = edit_article_title(tx, person_id, jsonData)
	case "add_article_by_title":
		ret = add_article_by_title(tx, person_id, jsonData)
	case "get_article_list":
		ret = get_article_list(tx, person_id, jsonData)
	case "get_single_article_in_list":
		ret = get_single_article_in_list(tx, person_id, jsonData)
	case "del_article":
		ret = del_article(tx, person_id, jsonData)
	case "add_article_comment":
		ret = add_article_comment(tx, person_id, jsonData)
	case "get_family_members":
		ret = get_family_members(tx, person_id, jsonData)
	case "family_add_father":
		ret = family_add_father(tx, person_id, jsonData)
	case "family_add_mother":
		ret = family_add_mother(tx, person_id, jsonData)
	case "family_add_husband":
		ret = family_add_husband(tx, person_id, jsonData)
	case "family_add_wife":
		ret = family_add_wife(tx, person_id, jsonData)
	case "family_add_brother":
		ret = family_add_brother(tx, person_id, jsonData)
	case "family_add_child":
		ret = family_add_child(tx, person_id, jsonData)
	case "family_delete_person":
		ret = family_delete_person(tx, person_id, jsonData)
	case "get_relation_person_info":
		ret = get_relation_person_info(tx, person_id, jsonData)
	case "get_relation_person_info_add":
		ret = get_relation_person_info_add(tx, person_id, jsonData)
	case "get_child_can_select_priorities":
		ret = get_child_can_select_priorities(tx, person_id, jsonData)
	case "get_brother_can_select_priorities":
		ret = get_brother_can_select_priorities(tx, person_id, jsonData)
	case "edit_relation_person_info":
		ret = edit_relation_person_info(tx, person_id, jsonData)
	case "get_family_article_info":
		ret = get_family_article_info(tx, person_id, jsonData)
	case "edit_family_article_info":
		ret = edit_family_article_info(tx, person_id, jsonData)
	case "add_family_article_by_title":
		ret = add_family_article_by_title(tx, person_id, jsonData)
	case "edit_family_article_title":
		ret = edit_family_article_title(tx, person_id, jsonData)
	case "get_family_article_list":
		ret = get_family_article_list(tx, person_id, jsonData)
	case "get_single_family_article_in_list":
		ret = get_single_family_article_in_list(tx, person_id, jsonData)
	case "del_family_article":
		ret = del_family_article(tx, person_id, jsonData)
	case "add_family_article_comment":
		ret = add_family_article_comment(tx, person_id, jsonData)
	default:
		ret = FailRet(CodeParamError, "no method")
	}
	return ret
}
